﻿/*
** Xin YUAN, 2023, BSD (2)
*/

////////////////////////////////////////////////////////////////////////////////

//for SIMD

#pragma pack(push, 16)

// _ij : i -- row  j -- column

//Mat2x2<T>

template <typename T>
class Mat2x2
{
public:
	typedef T  ValueType;

public:
	union {
#pragma pack(push, 1)
		struct { T _11, _21, _12, _22; } v;
#pragma pack(pop)
		Mat<T, 2, 2> data;
	};

	Mat2x2() noexcept
	{
	}
	Mat2x2(const Mat2x2<T>& src) noexcept : v(src.v)
	{
	}
	Mat2x2(const T& _11, const T& _21, const T& _12, const T& _22) noexcept : v{_11, _21, _12, _22}
	{
	}
	Mat2x2(const Vec2<T>& v1, const Vec2<T>& v2) noexcept : v{v1.v._1, v1.v._2, v2.v._1, v2.v._2}
	{
	}

	Mat2x2<T>& operator=(const Mat2x2<T>& src) noexcept
	{
		v = src.v;
		return *this;
	}

	Mat2x2<T>& Set(const T& _11, const T& _21, const T& _12, const T& _22) noexcept
	{
		v._11 = _11;
		v._21 = _21;
		v._12 = _12;
		v._22 = _22;
		return *this;
	}

	Mat2x2<T>& operator+=(const T& t) noexcept
	{
		v._11 += t;
		v._21 += t;
		v._12 += t;
		v._22 += t;
		return *this;
	}
	Mat2x2<T>& operator+=(const Mat2x2<T>& m) noexcept
	{
		v._11 += m.v._11;
		v._21 += m.v._21;
		v._12 += m.v._12;
		v._22 += m.v._22;
		return *this;
	}
	Mat2x2<T>& operator-=(const T& t) noexcept
	{
		v._11 -= t;
		v._21 -= t;
		v._12 -= t;
		v._22 -= t;
		return *this;
	}
	Mat2x2<T>& operator-=(const Mat2x2<T>& m) noexcept
	{
		v._11 -= m.v._11;
		v._21 -= m.v._21;
		v._12 -= m.v._12;
		v._22 -= m.v._22;
		return *this;
	}

	Mat2x2<T>& operator*=(const T& t) noexcept
	{
		v._11 *= t;
		v._21 *= t;
		v._12 *= t;
		v._22 *= t;
		return *this;
	}
	Mat2x2<T>& operator/=(const T& t) noexcept
	{
		v._11 /= t;
		v._21 /= t;
		v._12 /= t;
		v._22 /= t;
		return *this;
	}

	Mat2x2<T> operator+(const T& t) const noexcept
	{
		return Mat2x2<T>(v._11 + t, v._21 + t, v._12 + t, v._22 + t);
	}
	Mat2x2<T> operator+(const Mat2x2<T>& m) const noexcept
	{
		return Mat2x2<T>(v._11 + m.v._11, v._21 + m.v._21, v._12 + m.v._12, v._22 + m.v._22);
	}
	Mat2x2<T> operator-(const T& t) const noexcept
	{
		return Mat2x2<T>(v._11 - t, v._21 - t, v._12 - t, v._22 - t);
	}
	Mat2x2<T> operator-(const Mat2x2<T>& m) const noexcept
	{
		return Mat2x2<T>(v._11 - m.v._11, v._21 - m.v._21, v._12 - m.v._12, v._22 - m.v._22);
	}

	Mat2x2<T> operator*(const T& t) const noexcept
	{
		return Mat2x2<T>(v._11 * t, v._21 * t, v._12 * t, v._22 * t);
	}
	Mat2x2<T> operator/(const T& t) const noexcept
	{
		return Mat2x2<T>(v._11 / t, v._21 / t, v._12 / t, v._22 / t);
	}

	Mat2x2<T> operator-() const noexcept
	{
		return Mat2x2<T>(-v._11, -v._21, -v._12, -v._22);
	}
};

template <typename T>
inline Mat2x2<T> operator+(const T& t, const Mat2x2<T>& m) noexcept
{
	return Mat2x2<T>(t + m.v._11, t + m.v._21, t + m.v._12, t + m.v._22);
}
template <typename T>
inline Mat2x2<T> operator-(const T& t, const Mat2x2<T>& m) noexcept
{
	return Mat2x2<T>(t - m.v._11, t - m.v._21, t - m.v._12, t - m.v._22);
}
template <typename T>
inline Mat2x2<T> operator*(const T& t, const Mat2x2<T>& m) noexcept
{
	return Mat2x2<T>(t * m.v._11, t * m.v._21, t * m.v._12, t * m.v._22);
}
template <typename T>
inline Mat2x2<T> operator/(const T& t, const Mat2x2<T>& m) noexcept
{
	return Mat2x2<T>(t / m.v._11, t / m.v._21, t / m.v._12, t / m.v._22);
}

//Mat2x3<T>

template <typename T>
class Mat2x3
{
public:
	typedef T  ValueType;

public:
	union {
#pragma pack(push, 1)
		struct { T _11, _21, _31, _12, _22, _32; } v;
#pragma pack(pop)
		Mat<T, 2, 3> data;
	};

	Mat2x3() noexcept
	{
	}
	Mat2x3(const Mat2x3<T>& src) noexcept : v(src.v)
	{
	}
	Mat2x3(const T& _11, const T& _21, const T& _31, const T& _12, const T& _22, const T& _32) noexcept : v{_11, _21, _31, _12, _22, _32}
	{
	}
	Mat2x3(const Vec3<T>& v1, const Vec3<T>& v2) noexcept : v{v1.v._1, v1.v._2, v1.v._3, v2.v._1, v2.v._2, v2.v._3}
	{
	}

	Mat2x3<T>& operator=(const Mat2x3<T>& src) noexcept
	{
		v = src.v;
		return *this;
	}

	Mat2x3<T>& Set(const T& _11, const T& _21, const T& _31, const T& _12, const T& _22, const T& _32) noexcept
	{
		v._11 = _11;
		v._21 = _21;
		v._31 = _31;
		v._12 = _12;
		v._22 = _22;
		v._32 = _32;
		return *this;
	}

	Mat2x3<T>& operator+=(const T& t) noexcept
	{
		v._11 += t;
		v._21 += t;
		v._31 += t;
		v._12 += t;
		v._22 += t;
		v._32 += t;
		return *this;
	}
	Mat2x3<T>& operator+=(const Mat2x3<T>& m) noexcept
	{
		v._11 += m.v._11;
		v._21 += m.v._21;
		v._31 += m.v._31;
		v._12 += m.v._12;
		v._22 += m.v._22;
		v._32 += m.v._32;
		return *this;
	}
	Mat2x3<T>& operator-=(const T& t) noexcept
	{
		v._11 -= t;
		v._21 -= t;
		v._31 -= t;
		v._12 -= t;
		v._22 -= t;
		v._32 -= t;
		return *this;
	}
	Mat2x3<T>& operator-=(const Mat2x3<T>& m) noexcept
	{
		v._11 -= m.v._11;
		v._21 -= m.v._21;
		v._31 -= m.v._31;
		v._12 -= m.v._12;
		v._22 -= m.v._22;
		v._32 -= m.v._32;
		return *this;
	}

	Mat2x3<T>& operator*=(const T& t) noexcept
	{
		v._11 *= t;
		v._21 *= t;
		v._31 *= t;
		v._12 *= t;
		v._22 *= t;
		v._32 *= t;
		return *this;
	}
	Mat2x3<T>& operator/=(const T& t) noexcept
	{
		v._11 /= t;
		v._21 /= t;
		v._31 /= t;
		v._12 /= t;
		v._22 /= t;
		v._32 /= t;
		return *this;
	}

	Mat2x3<T> operator+(const T& t) const noexcept
	{
		return Mat2x3<T>(v._11 + t, v._21 + t, v._31 + t, v._12 + t, v._22 + t, v._32 + t);
	}
	Mat2x3<T> operator+(const Mat2x3<T>& m) const noexcept
	{
		return Mat2x3<T>(v._11 + m.v._11, v._21 + m.v._21, v._31 + m.v._31, v._12 + m.v._12, v._22 + m.v._22, v._32 + m.v._32);
	}
	Mat2x3<T> operator-(const T& t) const noexcept
	{
		return Mat2x3<T>(v._11 - t, v._21 - t, v._31 - t, v._12 - t, v._22 - t, v._32 - t);
	}
	Mat2x3<T> operator-(const Mat2x3<T>& m) const noexcept
	{
		return Mat2x3<T>(v._11 - m.v._11, v._21 - m.v._21, v._31 - m.v._31, v._12 - m.v._12, v._22 - m.v._22, v._32 - m.v._32);
	}

	Mat2x3<T> operator*(const T& t) const noexcept
	{
		return Mat2x3<T>(v._11 * t, v._21 * t, v._31 * t, v._12 * t, v._22 * t, v._32 * t);
	}
	Mat2x3<T> operator/(const T& t) const noexcept
	{
		return Mat2x3<T>(v._11 / t, v._21 / t, v._31 / t, v._12 / t, v._22 / t, v._32 / t);
	}

	Mat2x3<T> operator-() const noexcept
	{
		return Mat2x3<T>(-v._11, -v._21, -v._31, -v._12, -v._22, -v._32);
	}
};

template <typename T>
inline Mat2x3<T> operator+(const T& t, const Mat2x3<T>& m) noexcept
{
	return Mat2x3<T>(t + m.v._11, t + m.v._21, t + m.v._31, t + m.v._12, t + m.v._22, t + m.v._32);
}
template <typename T>
inline Mat2x3<T> operator-(const T& t, const Mat2x3<T>& m) noexcept
{
	return Mat2x3<T>(t - m.v._11, t - m.v._21, t - m.v._31, t - m.v._12, t - m.v._22, t - m.v._32);
}
template <typename T>
inline Mat2x3<T> operator*(const T& t, const Mat2x3<T>& m) noexcept
{
	return Mat2x3<T>(t * m.v._11, t * m.v._21, t * m.v._31, t * m.v._12, t * m.v._22, t * m.v._32);
}
template <typename T>
inline Mat2x3<T> operator/(const T& t, const Mat2x3<T>& m) noexcept
{
	return Mat2x3<T>(t / m.v._11, t / m.v._21, t / m.v._31, t / m.v._12, t / m.v._22, t / m.v._32);
}

//Mat2x4<T>

template <typename T>
class Mat2x4
{
public:
	typedef T  ValueType;

public:
	union {
#pragma pack(push, 1)
		struct { T _11, _21, _31, _41, _12, _22, _32, _42; } v;
#pragma pack(pop)
		Mat<T, 2, 4> data;
	};

	Mat2x4() noexcept
	{
	}
	Mat2x4(const Mat2x4<T>& src) noexcept : v(src.v)
	{
	}
	Mat2x4(const T& _11, const T& _21, const T& _31, const T& _41, const T& _12, const T& _22, const T& _32, const T& _42) noexcept : v{_11, _21, _31, _41, _12, _22, _32, _42}
	{
	}
	Mat2x4(const Vec4<T>& v1, const Vec4<T>& v2) noexcept : v{v1.v._1, v1.v._2, v1.v._3, v1.v._4, v2.v._1, v2.v._2, v2.v._3, v2.v._4}
	{
	}

	Mat2x4<T>& operator=(const Mat2x4<T>& src) noexcept
	{
		v = src.v;
		return *this;
	}

	Mat2x4<T>& Set(const T& _11, const T& _21, const T& _31, const T& _41, const T& _12, const T& _22, const T& _32, const T& _42) noexcept
	{
		v._11 = _11;
		v._21 = _21;
		v._31 = _31;
		v._41 = _41;
		v._12 = _12;
		v._22 = _22;
		v._32 = _32;
		v._42 = _42;
		return *this;
	}

	Mat2x4<T>& operator+=(const T& t) noexcept
	{
		v._11 += t;
		v._21 += t;
		v._31 += t;
		v._41 += t;
		v._12 += t;
		v._22 += t;
		v._32 += t;
		v._42 += t;
		return *this;
	}
	Mat2x4<T>& operator+=(const Mat2x4<T>& m) noexcept
	{
		v._11 += m.v._11;
		v._21 += m.v._21;
		v._31 += m.v._31;
		v._41 += m.v._41;
		v._12 += m.v._12;
		v._22 += m.v._22;
		v._32 += m.v._32;
		v._42 += m.v._42;
		return *this;
	}
	Mat2x4<T>& operator-=(const T& t) noexcept
	{
		v._11 -= t;
		v._21 -= t;
		v._31 -= t;
		v._41 -= t;
		v._12 -= t;
		v._22 -= t;
		v._32 -= t;
		v._42 -= t;
		return *this;
	}
	Mat2x4<T>& operator-=(const Mat2x4<T>& m) noexcept
	{
		v._11 -= m.v._11;
		v._21 -= m.v._21;
		v._31 -= m.v._31;
		v._41 -= m.v._41;
		v._12 -= m.v._12;
		v._22 -= m.v._22;
		v._32 -= m.v._32;
		v._42 -= m.v._42;
		return *this;
	}

	Mat2x4<T>& operator*=(const T& t) noexcept
	{
		v._11 *= t;
		v._21 *= t;
		v._31 *= t;
		v._41 *= t;
		v._12 *= t;
		v._22 *= t;
		v._32 *= t;
		v._42 *= t;
		return *this;
	}
	Mat2x4<T>& operator/=(const T& t) noexcept
	{
		v._11 /= t;
		v._21 /= t;
		v._31 /= t;
		v._41 /= t;
		v._12 /= t;
		v._22 /= t;
		v._32 /= t;
		v._42 /= t;
		return *this;
	}

	Mat2x4<T> operator+(const T& t) const noexcept
	{
		return Mat2x4<T>(v._11 + t, v._21 + t, v._31 + t, v._41 + t, v._12 + t, v._22 + t, v._32 + t, v._42 + t);
	}
	Mat2x4<T> operator+(const Mat2x4<T>& m) const noexcept
	{
		return Mat2x4<T>(v._11 + m.v._11, v._21 + m.v._21, v._31 + m.v._31, v._41 + m.v._41, v._12 + m.v._12, v._22 + m.v._22, v._32 + m.v._32, v._42 + m.v._42);
	}
	Mat2x4<T> operator-(const T& t) const noexcept
	{
		return Mat2x4<T>(v._11 - t, v._21 - t, v._31 - t, v._41 - t, v._12 - t, v._22 - t, v._32 - t, v._42 - t);
	}
	Mat2x4<T> operator-(const Mat2x4<T>& m) const noexcept
	{
		return Mat2x4<T>(v._11 - m.v._11, v._21 - m.v._21, v._31 - m.v._31, v._41 - m.v._41, v._12 - m.v._12, v._22 - m.v._22, v._32 - m.v._32, v._42 - m.v._42);
	}

	Mat2x4<T> operator*(const T& t) const noexcept
	{
		return Mat2x4<T>(v._11 * t, v._21 * t, v._31 * t, v._41 * t, v._12 * t, v._22 * t, v._32 * t, v._42 * t);
	}
	Mat2x4<T> operator/(const T& t) const noexcept
	{
		return Mat2x4<T>(v._11 / t, v._21 / t, v._31 / t, v._41 / t, v._12 / t, v._22 / t, v._32 / t, v._42 / t);
	}

	Mat2x4<T> operator-() const noexcept
	{
		return Mat2x4<T>(-v._11, -v._21, -v._31, -v._41, -v._12, -v._22, -v._32, -v._42);
	}
};

template <typename T>
inline Mat2x4<T> operator+(const T& t, const Mat2x4<T>& m) noexcept
{
	return Mat2x4<T>(t + m.v._11, t + m.v._21, t + m.v._31, t + m.v._41, t + m.v._12, t + m.v._22, t + m.v._32, t + m.v._42);
}
template <typename T>
inline Mat2x4<T> operator-(const T& t, const Mat2x4<T>& m) noexcept
{
	return Mat2x4<T>(t - m.v._11, t - m.v._21, t - m.v._31, t - m.v._41, t - m.v._12, t - m.v._22, t - m.v._32, t - m.v._42);
}
template <typename T>
inline Mat2x4<T> operator*(const T& t, const Mat2x4<T>& m) noexcept
{
	return Mat2x4<T>(t * m.v._11, t * m.v._21, t * m.v._31, t * m.v._41, t * m.v._12, t * m.v._22, t * m.v._32, t * m.v._42);
}
template <typename T>
inline Mat2x4<T> operator/(const T& t, const Mat2x4<T>& m) noexcept
{
	return Mat2x4<T>(t / m.v._11, t / m.v._21, t / m.v._31, t / m.v._41, t / m.v._12, t / m.v._22, t / m.v._32, t / m.v._42);
}

#pragma pack(pop)

typedef Mat2x2<int32_t>   Mat2x2i;
typedef Mat2x2<uint32_t>  Mat2x2u;
typedef Mat2x2<float>     Mat2x2f;
typedef Mat2x2<double>    Mat2x2d;

typedef Mat2x3<int32_t>   Mat2x3i;
typedef Mat2x3<uint32_t>  Mat2x3u;
typedef Mat2x3<float>     Mat2x3f;
typedef Mat2x3<double>    Mat2x3d;

typedef Mat2x4<int32_t>   Mat2x4i;
typedef Mat2x4<uint32_t>  Mat2x4u;
typedef Mat2x4<float>     Mat2x4f;
typedef Mat2x4<double>    Mat2x4d;

////////////////////////////////////////////////////////////////////////////////
